import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;

class NotificationService {
  static final NotificationService instance = NotificationService._internal();

  NotificationService._internal();

  final FlutterLocalNotificationsPlugin _notifications =
      FlutterLocalNotificationsPlugin();

  Future<void> showNotification({
    required int id,
    required String title,
    required String body,
    String? payload,
  }) async {
    const AndroidNotificationDetails androidDetails =
        AndroidNotificationDetails(
          'baby_health_tracker_channel',
          '宝宝健康提醒',
          channelDescription: '宝宝的喂养、服药等提醒通知',
          importance: Importance.max,
          priority: Priority.high,
          showWhen: true,
        );

    const NotificationDetails details = NotificationDetails(
      android: androidDetails,
    );

    await _notifications.show(id, title, body, details, payload: payload);
  }

  Future<void> scheduleNotification({
    required int id,
    required String title,
    required String body,
    required DateTime scheduledDate,
    String? payload,
    bool repeats = false,
    RepeatInterval? repeatInterval,
  }) async {
    final AndroidNotificationDetails androidDetails =
        AndroidNotificationDetails(
          'baby_health_tracker_channel',
          '宝宝健康提醒',
          channelDescription: '宝宝的喂养、服药等提醒通知',
          importance: Importance.max,
          priority: Priority.high,
          showWhen: true,
        );

    final NotificationDetails details = NotificationDetails(
      android: androidDetails,
    );

    if (repeats && repeatInterval != null) {
      // For repeating notifications
      DateTime scheduleTime = _nextInstanceOf(scheduledDate, repeatInterval);

      await _notifications.zonedSchedule(
        id,
        title,
        body,
        tz.TZDateTime.from(scheduleTime, tz.local),
        details,
        matchDateTimeComponents: _getDateTimeComponents(repeatInterval),
        payload: payload,
        androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
      );
    } else {
      // For one-time notifications
      await _notifications.zonedSchedule(
        id,
        title,
        body,
        tz.TZDateTime.from(scheduledDate, tz.local),
        details,
        androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
        payload: payload,
      );
    }
  }

  Future<void> scheduleHealthReminder({
    required int id,
    required String babyName,
    required String type,
    required DateTime scheduledTime,
    String? notes,
    bool repeats = false,
    RepeatInterval? repeatInterval,
  }) async {
    final String title = '${babyName}的${_getTypeText(type)}提醒';
    final String body = notes ?? '该${_getTypeText(type)}啦';

    await scheduleNotification(
      id: id,
      title: title,
      body: body,
      scheduledDate: scheduledTime,
      payload: 'type:$type,id:$id',
      repeats: repeats,
      repeatInterval: repeatInterval,
    );
  }

  String _getTypeText(String type) {
    switch (type) {
      case 'feeding':
        return '喂养';
      case 'medicine':
        return '服药';
      case 'sleep':
        return '睡眠';
      case 'temperature':
        return '测温';
      case 'diaper':
        return '换尿布';
      default:
        return '健康';
    }
  }

  // Helper method to determine DateTimeComponents for repeating notifications
  DateTimeComponents? _getDateTimeComponents(RepeatInterval interval) {
    switch (interval) {
      case RepeatInterval.daily:
        return DateTimeComponents.time;
      case RepeatInterval.weekly:
        return DateTimeComponents.dayOfWeekAndTime;
      case RepeatInterval.everyMinute:
        return null;
      case RepeatInterval.hourly:
        return DateTimeComponents.time;
      default:
        return null;
    }
  }

  // Helper method to get next valid DateTime for scheduling
  tz.TZDateTime _nextInstanceOf(DateTime dateTime, RepeatInterval? interval) {
    final tz.TZDateTime now = tz.TZDateTime.now(tz.local);
    tz.TZDateTime scheduledDate = tz.TZDateTime.from(dateTime, tz.local);

    if (scheduledDate.isBefore(now)) {
      if (interval == null) {
        // For one-time notifications, just schedule for the next minute
        scheduledDate = tz.TZDateTime.from(
          DateTime.now().add(const Duration(minutes: 1)),
          tz.local,
        );
      } else {
        // For repeating notifications
        switch (interval) {
          case RepeatInterval.daily:
            scheduledDate = scheduledDate.add(const Duration(days: 1));
            break;
          case RepeatInterval.weekly:
            scheduledDate = scheduledDate.add(const Duration(days: 7));
            break;
          case RepeatInterval.everyMinute:
            scheduledDate = tz.TZDateTime.from(
              DateTime.now().add(const Duration(minutes: 1)),
              tz.local,
            );
            break;
          case RepeatInterval.hourly:
            scheduledDate = tz.TZDateTime.from(
              DateTime.now().add(const Duration(hours: 1)),
              tz.local,
            );
            break;
        }
      }
    }

    return scheduledDate;
  }

  Future<void> cancelNotification(int id) async {
    await _notifications.cancel(id);
  }

  Future<void> cancelAllNotifications() async {
    await _notifications.cancelAll();
  }

  Future<void> cancelReminder(int id) async {
    await _notifications.cancel(id);
  }

  Future<void> cancelAllReminders() async {
    await _notifications.cancelAll();
  }

  // Initialize timezone without flutter_native_timezone
  static Future<void> initializeTimeZone() async {
    tz.initializeTimeZones();
    // Use device's local timezone
    final String timeZoneName = DateTime.now().timeZoneName;
    try {
      tz.setLocalLocation(tz.getLocation(timeZoneName));
    } catch (e) {
      // Fallback to UTC if timezone is not found
      debugPrint('Timezone $timeZoneName not found, using UTC');
      tz.setLocalLocation(tz.UTC);
    }
  }
}
